/**
 * 
 */
package engine.expression;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.TreeMap;

import patern.Patern;
import patern.Rewriter;
import patern.RewriterPool;
import utilities.Trio;
import engine.expression.exceptions.CanTAddChildrenException;
import engine.expression.exceptions.DonTHaveChildrenException;

/**
 * @author valentin
 *
 */
public interface Expression
{
	public double value();
	public Operators operator();
	
	public boolean isConstante();
	
	public default Expression left()
	{
		throw new DonTHaveChildrenException();
	}
	
	public default Expression right()
	{
		throw new DonTHaveChildrenException();
	}
	
	public default void setLeft(Expression e)
	{
		throw new CanTAddChildrenException();
	}
	
	public default void setRight(Expression e)
	{
		throw new CanTAddChildrenException();
	}
	
	public default void removeLeft()
	{
		throw new DonTHaveChildrenException();
	}
	
	public default void removeRight()
	{
		throw new DonTHaveChildrenException();
	}
	
	public Trio<Operators, Double, Expression> reduceNumber();
	
	public boolean isCalculable();
	
	public static Expression reduce(Expression exp)
	{
		Trio<Operators, Double, Expression> reduc = exp.reduceNumber();
		System.out.println(reduc);
		
		if(reduc.x == null) // C'est une constante
		{
			if(reduc.z == null) // C'est un nombre
				return new Constante(reduc.y);
			else //C'est autre chose
				return reduc.z;
		}
		else
			return new Operator(reduc.x, new Constante(reduc.y), reduc.z);	
	}
	
	public static Expression simplify(Expression exp)
	{
		ArrayList<Rewriter> rewriters = RewriterPool.getPool();
		boolean simpDone = true;
		Rewriter r;
		Expression expSimp;
		
		while(simpDone)
		{
			for(Iterator<Rewriter> it = rewriters.iterator(); it.hasNext();)
			{
				simpDone = false;
				r = it.next();
				expSimp = r.filter(exp);
				
				if(expSimp != null)
				{
					exp = expSimp;
					simpDone = true;
				}
			}
		}
		
		return exp;
	}
}
